package com.itheima.easy.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.itheima.easy.base.UserAuth;
import com.itheima.easy.constant.UserCacheConstant;
import com.itheima.easy.security.JwtTokenManager;
import com.itheima.easy.service.*;
import com.itheima.easy.utils.EmptyUtil;
import com.itheima.easy.vo.DeptPostUserVo;
import com.itheima.easy.vo.ResourceVo;
import com.itheima.easy.vo.RoleVo;
import com.itheima.easy.vo.UserVo;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @ClassName LoginFacedImpl.java
 * @Description 登录接口实现
 */
@Component
public class LoginServiceImpl implements LoginService {

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    RoleService roleService;

    @Autowired
    ResourceService resourceService;

    @Autowired
    DeptPostUserService deptPostUserService;

    @Autowired
    RoleDeptService roleDeptService;

    @Autowired
    JwtTokenManager jwtTokenManager;

    @Autowired
    RedissonClient redissonClient;

    @Override
    public UserVo login(UserVo userVo) {
        //用户认证
        UsernamePasswordAuthenticationToken authentication =
            new UsernamePasswordAuthenticationToken(userVo.getUsername(), userVo.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authentication);

        //认证Authentication对象获得内置对象UserAuth
        UserAuth userAuth = (UserAuth) authenticate.getPrincipal();
        UserVo userVoResult = new UserVo();
        userVoResult.setId( Long.valueOf(userAuth.getId()));
        BeanUtils.copyProperties(userAuth, userVoResult);
        //用户当前角色
        List<RoleVo> roleVoList = roleService.findRoleVoListByUserId(userVoResult.getId());
        userVoResult.setRoleList(roleVoList);
        Set<String> roleLabels = roleVoList.stream().map(RoleVo::getLabel).collect(Collectors.toSet());
        userVoResult.setRoleLabels(roleLabels);

        //用户当前资源
        List<ResourceVo> resourceVoList = resourceService.findResourceVoListByUserId(userVoResult.getId());
        Set<String> requestPaths = resourceVoList.stream().map(ResourceVo::getRequestPath).collect(Collectors.toSet());
        userVoResult.setResourceRequestPaths(requestPaths);

        //用户当前数据权限
        /*DataSecurity dataSecurity = roleDeptService.findDataSecurityByUserId(roleVoList,userVoResult.getId());
        userVoResult.setDataSecurity(dataSecurity);*/

        //查询默认部门、职位
        DeptPostUserVo defaultDeptPostUserVo = deptPostUserService.findDeptPostUserVoByUserId(userVoResult.getId());
        if (!EmptyUtil.isNullOrEmpty(defaultDeptPostUserVo)){
            userVoResult.setDeptNo(defaultDeptPostUserVo.getDeptNo());
            userVoResult.setPostNo(defaultDeptPostUserVo.getPostNo());
        }

        //userToken令牌颁布
        String userToken = UUID.randomUUID().toString();
        userVoResult.setUserToken(userToken);

        //构建载荷
        Map<String,Object> claims = new HashMap<>();
        String userVoJsonString= JSONObject.toJSONString(userVoResult);
        claims.put("currentUser",userVoJsonString);

        //jwtToken令牌颁布
        String jwtToken = jwtTokenManager.issuedToken("system",
            jwtTokenManager.getJwtProperties().getTtl(), userToken, claims);

        //剔除缓存：用户关联userToken
        String userTokenKey = UserCacheConstant.USER_TOKEN+userVo.getUsername();
        RBucket<String> userTokenBucket = redissonClient.getBucket(userTokenKey);
        long ttl = Long.valueOf(jwtTokenManager.getJwtProperties().getTtl())/1000;
        userTokenBucket.set(userToken,ttl, TimeUnit.SECONDS);

        //续期缓存：userToken关联jwtToken
        String jwtTokenKey = UserCacheConstant.JWT_TOKEN+userToken;
        RBucket<String> jwtTokenKeyBucket = redissonClient.getBucket(jwtTokenKey);
        jwtTokenKeyBucket.set(jwtToken,ttl, TimeUnit.SECONDS);
        return userVoResult;
    }
}
